package main

import (
	"bytes"
	"crypto/sha256"
	"fmt"
	"math/big"
)

type ProofOfWork struct {
	//区块数据
	block Block
	//⽬标值，先写成固定的值，后⾯再进⾏推到演算。
	target big.Int
}

func NewProofOfWork(block Block) *ProofOfWork {
	pow := ProofOfWork{
		block: block,
	}
	//⾃定义的难度值，先写成固定值
	//0000100000000000000000000000000000000000000000000000000000000000
	targetString := "0000100000000000000000000000000000000000000000000000000000000000"
	//不要连着写
	bigIntTmp := big.Int{}
	//bigIntTmp.SetBytes([]byte(targetString))
	bigIntTmp.SetString(targetString, 16)
	pow.target = bigIntTmp
	return &pow
}

// - 提供⼀个计算哈希值的⽅法
// Run()
func (pow *ProofOfWork) Run() ([]byte, uint64) {
	//var data = "helloworld"
	////10s中左右
	//for i := 0; i < 1000000; i++ {
	// hash := sha256.Sum256([]byte(data + string(i)))
	// fmt.Printf("hash : %x, %d\n", string(hash[:]), i)
	//}
	var Nonce uint64
	var hash [32]byte
	fmt.Printf("target : %x\n", pow.target)
	for {
		//[Size]byte
		hash = sha256.Sum256(pow.prepareData(Nonce))
		//⽐较：当前的哈希值[32]byte，⽬标值：big.Int
		//⽬标是：把当前的哈希值转换成big.Int
		tTmp := big.Int{}
		tTmp.SetBytes(hash[:])
		// Cmp compares x and y and returns:
		//
		// -1 if x < y
		// 0 if x == y
		// +1 if x > y
		//
		//func (x *Int) Cmp(y *Int) (r int) {
		//当前哈希.Cmp(⽬标值) == -1，说明当前的哈希⼩于⽬标值
		if tTmp.Cmp(&pow.target) == -1 {
			//if tTmp < pow.target {
			//找到了，退出
			fmt.Printf("found hash : %x, %d\n", hash, Nonce)
			break
		} else {
			//继续循环
			Nonce++
		}
	}
	return hash[:], Nonce
}

func (pow *ProofOfWork) prepareData(num uint64) []byte {
	block := pow.block
	tmp := [][]byte{
		Uint64ToByte(block.Version),
		block.PrevHash,
		//block.Hash,
		block.MerKleRoot,
		Uint64ToByte(block.Timestamp),
		Uint64ToByte(block.Difficulty),
		Uint64ToByte(num),
		block.Data}
	data := bytes.Join(tmp, []byte{})
	return data
}
